﻿using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;

namespace MicroCloud.Utils
{
    /// <summary>
    /// 数据处理辅助扩展操作
    /// </summary>
    public static class DataExtensions
    {
        #region 方法
        /// <summary>
        /// 将DataSet中第一个DataTable转换为指定类型数据
        /// </summary>
        /// <typeparam name="T">要转换的数据实体类型</typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static List<T> ToModel<T>(this DataSet ds) where T : class, new()
        {
            if (ds == null || ds.Tables[0] == null || ds.Tables[0].Rows.Count == 0)
            {
                return null;
            }
            else
            {
                return ToModel<T>(ds.Tables[0]);
            }
        }
        
        /// <summary>
        /// 将DataSet中指定Index的DataTable转换为指定类型数据
        /// </summary>
        /// <typeparam name="T">要转换的数据实体类型</typeparam>
        /// <param name="ds"></param>
        /// <param name="index">DataTable的索引位置</param>
        /// <returns></returns>
        public static List<T> ToModel<T>(this DataSet ds, int index) where T : class, new()
        {
            if (ds == null || ds.Tables.Count <= index || index < 0 || ds.Tables[index] == null || ds.Tables[index].Rows.Count <= 0)
            {
                return null;
            }
            return ToModel<T>(ds.Tables[index]);
        }

        /// <summary>
        /// 将DataSet中指定名称的DataTable转换为指定类型数据
        /// </summary>
        /// <typeparam name="T">要转换的数据实体类型</typeparam>
        /// <param name="ds"></param>
        /// <param name="tableName">DataTable的名称</param>
        /// <returns></returns>
        public static List<T> ToModel<T>(this DataSet ds, string tableName) where T : class, new()
        {
            if (ds == null || ds.Tables.Count <= 0 || ds.Tables[tableName] == null || ds.Tables[tableName].Rows.Count <= 0)
            {
                return null;
            }
            return ToModel<T>(ds.Tables[tableName]);
        }

        /// <summary>
        /// 将DataTable转换为指定类型数据
        /// </summary>
        /// <typeparam name="T">要转换的数据实体类型</typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<T> ToModel<T>(this DataTable dt) where T : class, new()
        {
            //定义集合
            List<T> modelList = new();
            if (dt == null || dt.Rows.Count <= 0)
            {
                return modelList;
            }
            //获得此模型的公共属性
            PropertyInfo[] propertyInfos = typeof(T).GetProperties();
            foreach (DataRow dr in dt.Rows)
            {
                //T model = (T)Activator.CreateInstance(typeof(T));  
                T model = new();
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    //定义临时变量
                    //将属性名称赋值给临时变量
                    string tempName = propertyInfo.Name;
                    //检查DataTable是否包含此列
                    if (dt.Columns.Contains(tempName))
                    {
                        //该属性不可写,直接跳出
                        if (!propertyInfo.CanWrite) { continue; }
                        //取值 
                        object value = dr[tempName];
                        //如果非NULL,则赋值给对象的属性
                        if (value is DBNull || value != DBNull.Value)
                        {
                            #region "赋值"
                            switch (propertyInfo.PropertyType.ToString().ToLower().Trim())
                            {
                                case "system.string":
                                    propertyInfo.SetValue(model, Convert.ToString(value), null);
                                    break;
                                case "system.int32":
                                    propertyInfo.SetValue(model, Convert.ToInt32(value), null);
                                    break;
                                case "system.int64":
                                    propertyInfo.SetValue(model, Convert.ToInt64(value), null);
                                    break;
                                case "system.datetime":
                                    propertyInfo.SetValue(model, Convert.ToDateTime(value), null);
                                    break;
                                case "system.boolean":
                                    propertyInfo.SetValue(model, Convert.ToBoolean(value), null);
                                    break;
                                case "system.double":
                                    propertyInfo.SetValue(model, Convert.ToDouble(value), null);
                                    break;
                                case "system.decimal":
                                    propertyInfo.SetValue(model, Convert.ToDecimal(value), null);
                                    break;
                                default:
                                    propertyInfo.SetValue(model, value, null);
                                    break;
                            }
                            #endregion
                        }
                    }
                }

                modelList.Add(model);
            }
            return modelList;
        }

        /// <summary>
        /// 将DataRow转换为指定类型数据
        /// </summary>
        /// <typeparam name="T">要转换的数据实体类型</typeparam>
        /// <param name="dr"></param>
        /// <returns></returns>
        public static T ToModel<T>(this DataRow dr) where T : class, new()
        {
            if (dr == null)
            {
                return default;
            }

            //T model = (T)Activator.CreateInstance(typeof(T));  
            T model = new();
            //获得此模型的公共属性
            PropertyInfo[] propertyInfos = typeof(T).GetProperties();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                //定义临时变量
                //将属性名称赋值给临时变量
                string tempName = propertyInfo.Name;
                //检查DataTable是否包含此列
                if (dr.Table.Columns.Contains(tempName))
                {
                    //该属性不可写,直接跳出
                    if (!propertyInfo.CanWrite) { continue; }
                    //取值 
                    object value = dr[tempName];
                    //如果非NULL,则赋值给对象的属性
                    if (value is DBNull || value != DBNull.Value)
                    {
                        #region "赋值"
                        switch (propertyInfo.PropertyType.ToString().ToLower().Trim())
                        {
                            case "system.string":
                                propertyInfo.SetValue(model, Convert.ToString(value), null);
                                break;
                            case "system.int32":
                                propertyInfo.SetValue(model, Convert.ToInt32(value), null);
                                break;
                            case "system.int64":
                                propertyInfo.SetValue(model, Convert.ToInt64(value), null);
                                break;
                            case "system.datetime":
                                propertyInfo.SetValue(model, Convert.ToDateTime(value), null);
                                break;
                            case "system.boolean":
                                propertyInfo.SetValue(model, Convert.ToBoolean(value), null);
                                break;
                            case "system.double":
                                propertyInfo.SetValue(model, Convert.ToDouble(value), null);
                                break;
                            case "system.decimal":
                                propertyInfo.SetValue(model, Convert.ToDecimal(value), null);
                                break;
                            default:
                                propertyInfo.SetValue(model, value, null);
                                break;
                        }
                        #endregion
                    }
                }
            }

            return model;
        }

        /// <summary>
        /// 实体类转换成DataSet
        /// </summary>
        /// <param name="modelList">实体类列表</param>
        /// <returns></returns>
        public static DataSet ToDataSet<T>(this List<T> modelList) where T : class, new()
        {
            if (modelList == null || modelList.Count <= 0)
            {
                return null;
            }
            DataSet ds = new();
            ds.Tables.Add(ToDataTable<T>(modelList));
            return ds;
        }

        /// <summary>
        /// 将指定类型数据转换为DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="modelList"></param>
        /// <returns></returns>
        public static DataTable ToDataTable<T>(this IList<T> modelList)
        {
            if (modelList == null || modelList.Count <= 0)
            {
                return null;
            }
            DataTable dt = CreateDataTable<T>();

            foreach (T model in modelList)
            {
                DataRow dataRow = dt.NewRow();
                var propertyInfos = typeof(T).GetProperties();
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    if (!propertyInfo.PropertyType.IsClass)
                    {
                        dataRow[propertyInfo.Name] = propertyInfo.GetValue(model, null);
                    }
                }
                dt.Rows.Add(dataRow);
            }
            return dt;
        }

        /// <summary>
        /// 将DataSet转换为结构对象
        /// </summary>
        /// <param name="ds">数据集</param>
        /// <returns>结构对象</returns>
        public static DataSetSchema ToSchema(this DataSet ds)
        {
            if (ds == null)
            {
                return null;
            }
            DataSetSchema schema = new() { Name = ds.DataSetName };
            for (int i = 0; i < ds.Tables.Count; i++)
            {
                var table = ds.Tables[i];
                schema.Tables.Add(table.ToSchema());
            }
            //foreach (DataTable table in ds.Tables) { }
            return schema;
        }

        /// <summary>
        /// 将DataTable转换为结构对象
        /// </summary>
        /// <param name="dt">数据表</param>
        /// <returns>结构对象</returns>
        public static DataTableSchema ToSchema(this DataTable dt)
        {
            if (dt == null)
            {
                return null;
            }
            DataTableSchema schema = new() { Name = dt.TableName };
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                var column = dt.Columns[i];
                schema.Columns.Add(new DataColumnSchema
                {
                    Name = column.ColumnName,
                    Display = column.Caption,
                    DataType = column.DataType,
                });
            }
            //foreach (DataColumn column in dt.Columns) { }
            return schema;
        }

        /// <summary>
        /// 将DataSet转换为Html字符串
        /// </summary>
        /// <param name="ds">数据集</param>
        /// <returns>Html字符串</returns>
        public static string ToHtmlString(this DataSet ds)
        {
            string htmltext = "";
            if (ds == null)
            {
                return htmltext;
            }
            for (int i = 0; i < ds.Tables.Count; i++)
            {
                var table = ds.Tables[i];
                htmltext = $@"{htmltext} <br />
{table.ToHtmlString()}";
            }
            return htmltext;
        }

        /// <summary>
        /// 将DataTable转换为Html字符串
        /// </summary>
        /// <param name="dt">数据表</param>
        /// <returns>Html字符串</returns>
        public static string ToHtmlString(this DataTable dt)
        {
            if (dt == null)
            {
                return "";
            }
            StringBuilder strHTMLBuilder = new();
            strHTMLBuilder.Append("<table border='1px' cellpadding='1' cellspacing='1' bgcolor='lightyellow' style='font-family:Garamond; font-size:smaller'>");

            strHTMLBuilder.Append("<tr >");
            foreach (DataColumn myColumn in dt.Columns)
            {
                strHTMLBuilder.Append("<td >");
                strHTMLBuilder.Append(myColumn.ColumnName);
                strHTMLBuilder.Append("</td>");

            }
            strHTMLBuilder.Append("</tr>");

            foreach (DataRow myRow in dt.Rows)
            {

                strHTMLBuilder.Append("<tr >");
                foreach (DataColumn myColumn in dt.Columns)
                {
                    strHTMLBuilder.Append("<td >");
                    strHTMLBuilder.Append(myRow[myColumn.ColumnName].ToString());
                    strHTMLBuilder.Append("</td>");

                }
                strHTMLBuilder.Append("</tr>");
            }

            //Close tags.
            strHTMLBuilder.Append("</table>");

            string htmltext = strHTMLBuilder.ToString();
            return htmltext;
        }

        /// <summary>
        /// 将DataSet转换为Excel文件Base64字符转
        /// </summary>
        /// <param name="ds">数据集</param>
        /// <param name="format">格式类型</param>
        /// <returns>Excel文件Base64字符转</returns>
        public static string ToExcelBase64String(this DataSet ds, ExcelFormat format = ExcelFormat.XLSX)
        {
            if (ds?.Tables?.Count <= 0)
            {
                return null;
            }
            HSSFWorkbook xlsWorkbook = null;   // 创建Excel97-2003格式的工作簿
            XSSFWorkbook xlsxWorkbook = null;  // 创建Excel2007-2021及以后格式的工作簿
            switch (format)
            {
                case ExcelFormat.XLS:
                    xlsWorkbook = new HSSFWorkbook();   // 创建Excel97-2003格式的工作簿
                    foreach (DataTable dt in ds.Tables)
                    {
                        if (dt.Rows?.Count <= 0) { continue; }
                        CreateExcelSheet(xlsWorkbook, dt);
                    }
                    break;
                case ExcelFormat.XLSX:
                    xlsxWorkbook = new XSSFWorkbook();  // 创建Excel2007-2021及以后格式的工作簿
                    foreach (DataTable dt in ds.Tables)
                    {
                        if (dt.Rows?.Count <= 0) { continue; }
                        CreateExcelSheet(xlsxWorkbook, dt);
                    }
                    break;
            }
            if (xlsWorkbook?.NumberOfSheets <= 0 && xlsxWorkbook?.NumberOfSheets <= 0)
            {
                return null;
            }
            var excelStream = new MemoryStream();
            switch (format)
            {
                case ExcelFormat.XLS:
                    xlsWorkbook.Write(excelStream);//写入内存流
                    break;
                case ExcelFormat.XLSX:
                    xlsxWorkbook.Write(excelStream);//写入内存流
                    break;
            }
            return excelStream.ToBase64String();
        }

        /// <summary>
        /// 将DataTable转换为Excel文件Base64字符转
        /// </summary>
        /// <param name="dt">数据表</param>
        /// <param name="format">格式类型</param>
        /// <returns>Excel文件Base64字符转</returns>
        public static string ToExcelBase64String(this DataTable dt, ExcelFormat format = ExcelFormat.XLSX)
        {

            if (dt?.Rows?.Count <= 0)
            {
                return null;
            }
            HSSFWorkbook xlsWorkbook = null;   // 创建Excel97-2003格式的工作簿
            XSSFWorkbook xlsxWorkbook = null;  // 创建Excel2007-2021及以后格式的工作簿
            switch (format)
            {
                case ExcelFormat.XLS:
                    xlsWorkbook = new HSSFWorkbook();   // 创建Excel97-2003格式的工作簿
                    CreateExcelSheet(xlsWorkbook, dt);
                    break;
                case ExcelFormat.XLSX:
                    xlsxWorkbook = new XSSFWorkbook();  // 创建Excel2007-2021及以后格式的工作簿
                    CreateExcelSheet(xlsxWorkbook, dt);
                    break;
            }
            if (xlsWorkbook?.NumberOfSheets <= 0 && xlsxWorkbook?.NumberOfSheets <= 0)
            {
                return null;
            }
            var excelStream = new MemoryStream();
            switch (format)
            {
                case ExcelFormat.XLS:
                    xlsWorkbook.Write(excelStream);//写入内存流
                    break;
                case ExcelFormat.XLSX:
                    xlsxWorkbook.Write(excelStream);//写入内存流
                    break;
            }
            return excelStream.ToBase64String();
        }

        #endregion

        #region 私有方法
        /// <summary>
        /// 根据实体类型创建DataTable的结构
        /// </summary>
        /// <returns></returns>
        private static DataTable CreateDataTable<T>()
        {
            Type modelType = typeof(T);
            DataTable dataTable = new(modelType.Name);
            var propertyInfos = modelType.GetProperties();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (!propertyInfo.PropertyType.IsClass)
                {
                    dataTable.Columns.Add(new DataColumn(propertyInfo.Name, propertyInfo.PropertyType));
                }
            }
            return dataTable;
        }
        
        /// <summary>
        /// 创建Excel工作表
        /// </summary>
        /// <param name="workbook">Excel97-2003格式的工作簿</param>
        /// <param name="dt">数据表</param>
        private static void CreateExcelSheet(HSSFWorkbook workbook, DataTable dt)
        {
            if (workbook == null) { return; }
            if (dt?.Rows?.Count <= 0) { return; }
            var sheetName = dt.TableName.IsMissing() ? $"Sheet{workbook.NumberOfSheets + 1}" : dt.TableName;
            var sheet = workbook.CreateSheet(sheetName);   // 在工作簿中创建工作表
            int rowCount = dt.Rows.Count;//行数
            int columnCount = dt.Columns.Count;//列数
            //设置列头
            var row = sheet.CreateRow(0);//excel第一行设为列头
            ICell cell;
            for (int c = 0; c < columnCount; c++)
            {
                cell = row.CreateCell(c);
                cell.SetCellValue(dt.Columns[c].ColumnName);
            }
            //设置每行每列的单元格,
            for (int i = 0; i < rowCount; i++)
            {
                row = sheet.CreateRow(i + 1);
                for (int j = 0; j < columnCount; j++)
                {
                    cell = row.CreateCell(j);//excel第二行开始写入数据
                    cell.SetCellValue(dt.Rows[i][j].ToString());
                }
            }
        }
        
        /// <summary>
        /// 创建Excel工作表
        /// </summary>
        /// <param name="workbook">Excel2007-2021及以后格式的工作簿</param>
        /// <param name="dt">数据表</param>
        private static void CreateExcelSheet(XSSFWorkbook workbook, DataTable dt)
        {
            if (workbook == null) { return; }
            if (dt?.Rows?.Count <= 0) { return; }
            var sheetName = dt.TableName.IsMissing() ? $"Sheet{workbook.NumberOfSheets + 1}" : dt.TableName;
            var sheet = workbook.CreateSheet(sheetName);   // 在工作簿中创建工作表
            int rowCount = dt.Rows.Count;//行数
            int columnCount = dt.Columns.Count;//列数
            //设置列头
            var row = sheet.CreateRow(0);//excel第一行设为列头
            ICell cell;
            for (int c = 0; c < columnCount; c++)
            {
                cell = row.CreateCell(c);
                cell.SetCellValue(dt.Columns[c].ColumnName);
            }
            //设置每行每列的单元格,
            for (int i = 0; i < rowCount; i++)
            {
                row = sheet.CreateRow(i + 1);
                for (int j = 0; j < columnCount; j++)
                {
                    cell = row.CreateCell(j);//excel第二行开始写入数据
                    cell.SetCellValue(dt.Rows[i][j].ToString());
                }
            }
        }

        #endregion

    }

}
